using System;
using MxNetwork;
using GameTools;
using System.Globalization;
using System.Runtime.Remoting;
using System.Runtime.InteropServices;
using ServiceStack.Redis;
using PuSuoPai;
using ServiceStack.Redis.Generic;

namespace DTFight
{
	public class RoomMsg
	{
		static RoomMsg	mInstance = new RoomMsg();
		static public RoomMsg Instance()	{ return mInstance; }
		
		public void Init()
		{
			NetworkDispatcher.Instance.AddParser ((int)MSG_ROOM.ENTER_ROOM, OnParseEnterRoom);
			NetworkDispatcher.Instance.AddParser ((int)MSG_ROOM.EXIT_ROOM, OnParseExitRoom);

			NetworkDispatcher.Instance.AddParser ((int)MSG_ROOM.SELECT_ADVISER, OnParseSelectAdviser);
			NetworkDispatcher.Instance.AddParser ((int)MSG_ROOM.SELECT_BET_PLAYER, OnParseSelectBetPlayer);
			NetworkDispatcher.Instance.AddParser ((int)MSG_ROOM.SELECT_GROUP, OnParseSelectGroup);
			NetworkDispatcher.Instance.AddParser ((int)MSG_ROOM.BET_POINT, OnParseBetPoint);
		}

		public void Destroy()
		{
			NetworkDispatcher.Instance.RemoveParser ((int)MSG_ROOM.ENTER_ROOM, OnParseEnterRoom);
			NetworkDispatcher.Instance.RemoveParser ((int)MSG_ROOM.EXIT_ROOM, OnParseExitRoom);

			NetworkDispatcher.Instance.RemoveParser ((int)MSG_ROOM.SELECT_ADVISER, OnParseSelectAdviser);
			NetworkDispatcher.Instance.RemoveParser ((int)MSG_ROOM.SELECT_BET_PLAYER, OnParseSelectBetPlayer);
			NetworkDispatcher.Instance.RemoveParser ((int)MSG_ROOM.SELECT_GROUP, OnParseSelectGroup);
			NetworkDispatcher.Instance.RemoveParser ((int)MSG_ROOM.BET_POINT, OnParseBetPoint);
		}
		
	    public void SendError(MxNwkPacket pkt, MSG_ERROR error, string msg="")
		{
	        Log.WriteLog(pkt.GetRemoteIP().GetIP() + "ERROR: [" + pkt.GetPacketID().ToString() + "]" + NetMsgError.Instance().GetError((uint)error));

			MxNwkPacket ark = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_ACK);
			ark.SetPacketResult((UInt32)error);
	        ark.Write(msg);
			NetworkDispatcher.Instance.SendArk(pkt, ark);
		}

		void OnParseEnterRoom(MxNwkPacket pkt, MxNwkPacket pkt_rq)
		{
			ClientData client = ClientMgr.Instance ().GetClient (pkt.GetPacketChannelID ());
			if (client == null) {
				ClientMgr.Instance ().DisconnectClient (pkt.GetPacketChannelID ());
			}

			try {
				string playId = pkt.ReadString();
				int roomId = pkt.ReadInt32();

				var redis = RedisMgr.Instance.GetClient ().As<Player> ();
				Player curPlayer = redis.GetFromHash(playId);
				if (curPlayer == null)
				{
					SendError (pkt, MSG_ERROR.DATA_ERROR);
					return;
				}

				PlayerData player = new PlayerData();
				player.PlayerId = playId;
				player.Points = (UInt32)curPlayer.Points;
				player.ChannelId = pkt.GetPacketChannelID();
				client.Player = player;

				GameMgr.Instance.ExitRoom(client.Player);

				if (!GameMgr.Instance.EnterRoom(roomId, client.Player))
				{
					SendError (pkt, MSG_ERROR.ENTER_ROOM_FAILD);
					return;
				}

				// send ark
				MxNwkPacket ark = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_ACK);
				foreach (var time in GameData.WaiterTime)
				{
					ark.Write(time);
				}

				GameData.Read(ref ark, GameMgr.Instance.GetRoom(roomId));

				ark.Write(client.Player.PlayerId);
				ark.Write(client.Player.Points);
				NetworkDispatcher.Instance.SendArk(pkt, ark);
			}
			catch (Exception e)
			{
				Log.WriteLog ("EXCEPTION: " + e.ToString ());
				SendError (pkt, MSG_ERROR.UNKNOW_ERROR);
				return;
			}
		}

		void OnParseExitRoom(MxNwkPacket pkt, MxNwkPacket pkt_rq)
		{
			ClientData client = ClientMgr.Instance ().GetClient (pkt.GetPacketChannelID ());
			if (client == null) {
				ClientMgr.Instance ().DisconnectClient (pkt.GetPacketChannelID ());
			}

			try {

				GameMgr.Instance.ExitRoom(client.Player);

				// send ark
				MxNwkPacket ark = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_ACK);
				NetworkDispatcher.Instance.SendArk(pkt, ark);
			}
			catch (Exception e)
			{
				Log.WriteLog ("EXCEPTION: " + e.ToString ());
				SendError (pkt, MSG_ERROR.UNKNOW_ERROR);
				return;
			}
		}

		void OnParseSelectAdviser(MxNwkPacket pkt, MxNwkPacket pkt_rq)
		{
			ClientData client = ClientMgr.Instance ().GetClient (pkt.GetPacketChannelID ());
			if (client == null) {
				ClientMgr.Instance ().DisconnectClient (pkt.GetPacketChannelID ());
			}

			if (client.Player == null) {
				SendError (pkt, MSG_ERROR.UNKNOW_ERROR);
				return;
			}

			try {
				GameData room = GameMgr.Instance.GetRoom(client.Player.CurRoomId);

				if (room.CurStateInfo.StateFlag != GameData.STATE_FLAG.SELECT_GROUP)
				{
					SendError(pkt, MSG_ERROR.NOT_DO_THIS);
					return;
				}

				GameData.ADVISER_TYPE adviserType = (GameData.ADVISER_TYPE)pkt.ReadUInt32();

				UInt32 needPoint = 100;
				if (adviserType == GameData.ADVISER_TYPE.拉斯维加斯)
					needPoint = 200;
				else if (adviserType == GameData.ADVISER_TYPE.澳门)
					needPoint = 150;

				if (client.Player.Points < needPoint)
				{
					SendError(pkt, MSG_ERROR.NOT_ENOUGH_POINT);
					return;
				}

				client.Player.Points -= needPoint;

				GameData.GROUP_TYPE group = room.QueryAdviser(adviserType);

				// save db
				var redis = RedisMgr.Instance.GetClient ().As<Player> ();
				Player curPlayer = redis.GetFromHash(client.Player.PlayerId);
				curPlayer.Points = (int)client.Player.Points;
				redis.StoreAsHash(curPlayer);

				// send ark
				MxNwkPacket ark = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_ACK);
				ark.Write((UInt32)group);
				ark.Write(client.Player.Points);
				NetworkDispatcher.Instance.SendArk(pkt, ark);
			}
			catch (Exception e)
			{
				Log.WriteLog ("EXCEPTION: " + e.ToString ());
				SendError (pkt, MSG_ERROR.UNKNOW_ERROR);
				return;
			}
		}

		void OnParseSelectBetPlayer(MxNwkPacket pkt, MxNwkPacket pkt_rq)
		{
			ClientData client = ClientMgr.Instance ().GetClient (pkt.GetPacketChannelID ());
			if (client == null) {
				ClientMgr.Instance ().DisconnectClient (pkt.GetPacketChannelID ());
			}

			if (client.Player == null) {
				SendError (pkt, MSG_ERROR.UNKNOW_ERROR);
				return;
			}

			try {
				GameData room = GameMgr.Instance.GetRoom(client.Player.CurRoomId);

				if (room.CurStateInfo.StateFlag != GameData.STATE_FLAG.SELECT_GROUP)
				{
					SendError(pkt, MSG_ERROR.NOT_DO_THIS);
					return;
				}

				if (client.Player.Points < 100)
				{
					SendError(pkt, MSG_ERROR.NOT_ENOUGH_POINT);
					return;
				}

				string betPlayerId = pkt.ReadString();

				client.Player.Points -= 100;

				// save db
				var redis = RedisMgr.Instance.GetClient ().As<Player> ();
				Player curPlayer = redis.GetFromHash(client.Player.PlayerId);
				curPlayer.Points = (int)client.Player.Points;
				redis.StoreAsHash(curPlayer);

				// send ark
				MxNwkPacket ark = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_ACK);
				ark.Write(client.Player.Points);
				NetworkDispatcher.Instance.SendArk(pkt, ark);
			}
			catch (Exception e)
			{
				Log.WriteLog ("EXCEPTION: " + e.ToString ());
				SendError (pkt, MSG_ERROR.UNKNOW_ERROR);
				return;
			}
		}

		void OnParseSelectGroup(MxNwkPacket pkt, MxNwkPacket pkt_rq)
		{
			ClientData client = ClientMgr.Instance ().GetClient (pkt.GetPacketChannelID ());
			if (client == null) {
				ClientMgr.Instance ().DisconnectClient (pkt.GetPacketChannelID ());
			}

			if (client.Player == null) {
				SendError (pkt, MSG_ERROR.UNKNOW_ERROR);
				return;
			}

			try {
				GameData.GROUP_TYPE group = (GameData.GROUP_TYPE)pkt.ReadUInt32();

				GameData room = GameMgr.Instance.GetRoom(client.Player.CurRoomId);

				if (room.CurStateInfo.StateFlag != GameData.STATE_FLAG.SELECT_GROUP)
				{
					SendError(pkt, MSG_ERROR.NOT_DO_THIS);
					return;
				}

				if (room.GetPlayerGroup(client.Player) != GameData.GROUP_TYPE.MAX)
				{
					SendError(pkt, MSG_ERROR.NOT_REPEAT_THIS);
					return;
				}

				if (client.Player.Points < GameData.BASE_POINT)
				{
					SendError(pkt, MSG_ERROR.NOT_ENOUGH_POINT);
					return;
				}

				room.SelectGroup(client.Player, group);

				client.Player.Points -= GameData.BASE_POINT;

				// save db
				var redis = RedisMgr.Instance.GetClient ().As<Player> ();
				Player curPlayer = redis.GetFromHash(client.Player.PlayerId);
				curPlayer.Points = (int)client.Player.Points;
				redis.StoreAsHash(curPlayer);

				// send ark
				MxNwkPacket ark = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_ACK);
				ark.Write(client.Player.Points);
				NetworkDispatcher.Instance.SendArk(pkt, ark);
			}
			catch (Exception e)
			{
				Log.WriteLog ("EXCEPTION: " + e.ToString ());
				SendError (pkt, MSG_ERROR.UNKNOW_ERROR);
				return;
			}
		}

		void OnParseBetPoint(MxNwkPacket pkt, MxNwkPacket pkt_rq)
		{
			ClientData client = ClientMgr.Instance ().GetClient (pkt.GetPacketChannelID ());
			if (client == null) {
				ClientMgr.Instance ().DisconnectClient (pkt.GetPacketChannelID ());
			}

			try {
				UInt32 points = pkt.ReadUInt32();

				if (client.Player.Points < points)
				{
					SendError(pkt, MSG_ERROR.NOT_ENOUGH_POINT);
					return;
				}

				GameData room = GameMgr.Instance.GetRoom(client.Player.CurRoomId);

				if (room.CurStateInfo.StateFlag != GameData.STATE_FLAG.OPEN_NONE
					&& room.CurStateInfo.StateFlag != GameData.STATE_FLAG.OPEN_CARD_1
					&& room.CurStateInfo.StateFlag != GameData.STATE_FLAG.OPEN_CARD_2)
				{
					SendError(pkt, MSG_ERROR.NOT_DO_THIS);
					return;
				}

				byte rate = room.BetPoint(client.Player, points);
				if (rate == 0)
				{
					SendError(pkt, MSG_ERROR.BET_FAILD);
					return;
				}

				client.Player.Points -= points;

				// save db
				var redis = RedisMgr.Instance.GetClient ().As<Player> ();
				Player curPlayer = redis.GetFromHash(client.Player.PlayerId);
				curPlayer.Points = (int)client.Player.Points;
				redis.StoreAsHash(curPlayer);

				// send ark
				MxNwkPacket ark = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_ACK);
				ark.Write(rate);
				ark.Write(client.Player.BetPoints[rate - 1]);
				ark.Write(client.Player.Points);
				NetworkDispatcher.Instance.SendArk(pkt, ark);
			}
			catch (Exception e)
			{
				Log.WriteLog ("EXCEPTION: " + e.ToString ());
				SendError (pkt, MSG_ERROR.UNKNOW_ERROR);
				return;
			}
		}

		public void SendGameStart(GameData room)
		{
			MxNwkPacket msg = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_MESSAGE);
			msg.SetPacketID((UInt32)MSG_ROOM.GAME_START);
			BroadcastRoom (msg, room);
		}

		public void SendGameOver(GameData room, GameData.ResultInfo result)
		{
			MxNwkPacket msg = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_MESSAGE);
			msg.SetPacketID((UInt32)MSG_ROOM.GAME_OVER);
			GameData.ResultInfo.Read (ref msg, result);
			BroadcastRoom (msg, room);

			foreach (var playerRt in result.PlayerBetResults) {
				SendGameBetResult (playerRt.Player, (UInt32)playerRt.ResultPoint);
			}
		}

		public void SendGameBetResult(PlayerData player, UInt32 winPoints)
		{
			// save db
			var redis = RedisMgr.Instance.GetClient ().As<Player> ();
			Player curPlayer = redis.GetFromHash(player.PlayerId);
			curPlayer.Points = (int)player.Points;
			redis.StoreAsHash(curPlayer);

			// send
			MxNwkPacket msg = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_MESSAGE);
			msg.SetPacketID((UInt32)MSG_ROOM.BET_RESULT);
			msg.Write (player.Points);
			msg.Write (winPoints);
			NetworkDispatcher.Instance.SendMsg (player.ChannelId, msg);
		}

		public void SendGameShowCard(GameData room)
		{
			MxNwkPacket msg = new MxNwkPacket(MxNwkPacket.MxNwkPacketType.NPT_MESSAGE);
			msg.SetPacketID((UInt32)MSG_ROOM.GAME_SHOW_CARD);

			msg.Write ((UInt32)room.CurStateInfo.StateFlag);

			foreach (var card in room.DesktopCards) {
				if (card == null)
					msg.Write ((byte)0);
				else
					msg.Write (card.CardId);
			}
				
			BroadcastRoom (msg, room);
		}

		void BroadcastRoom(MxNwkPacket msg, GameData room)
		{
			foreach (var player in room.TotalPlayers) {
				NetworkDispatcher.Instance.SendMsg (player.Value.ChannelId, msg);
			}
		}
	}

}
